/* Regex.cpp
 *
 *  Author: Bematech S.A.
 */

#include "bilbao/util/Regex.h"

namespace bilbao
{
	namespace util
	{
		//--------------------------------------------------------------------------------
		// Construtor e Destrutor
		//--------------------------------------------------------------------------------
		Regex::Regex( void )
			: _regex(), _match(), _errorCode(0)
		{
			//Do nothing.
		}
		//--------------------------------------------------------------------------------
		Regex::~Regex( void )
		{
			//Do nothing.
		}
		//--------------------------------------------------------------------------------
		// Métodos Públicos
		//--------------------------------------------------------------------------------
		int Regex::match( RegexPair& result,
						  const char* regularExpression,
						  const char* message )
		{
			result.first = -1;
			result.second = -1;

			//Associa a expressão regular ao regex
			_errorCode = regcomp(&_regex, regularExpression, REG_EXTENDED);
			if ( _errorCode != 0/*OK*/ )
			{
				return _errorCode;
			}

			//Compara a mensagem com a expressão regular
			_errorCode = regexec(&_regex, message, 1, &_match, 0);

			if ( _errorCode == 0/*OK*/ )
			{
				result.first = _match.rm_so;
				result.second = _match.rm_eo;
			}

			return _errorCode;
		}
		//--------------------------------------------------------------------------------
		int Regex::allMatch( std::vector<RegexPair>& res,
				          	 const char* regularExpression,
				          	 const char* message )
		{
			int total = 0, pos = 0;

			//Associa a expressão regular ao regex
			if (( _errorCode = regcomp(&_regex, regularExpression, REG_EXTENDED)) != 0/*OK*/ )
			{
				return total;
			}

			//Compara a mensagem com a expressão regular
			_errorCode = regexec( &_regex, message, 1, &_match, 0 );

			while ( _errorCode == 0/*OK*/ )
			{
				//Soma a posição atual mais a posição do final da ocorrência anterior
				res.push_back(RegexPair(_match.rm_so+pos, _match.rm_eo+pos));
				pos += _match.rm_eo; //Atualiza início de string
				_errorCode = regexec( &_regex, message + pos, 1, &_match, REG_NOTBOL );
				total++;
			}

			return total;
		}
		//--------------------------------------------------------------------------------
		void Regex::getError( char* buffer )
		{
			getError( _errorCode, buffer );
		}
		//--------------------------------------------------------------------------------
		// Métodos Privados
		//--------------------------------------------------------------------------------
		void Regex::getError(int code, char* buffer)
		{
			//Pega o tamanho da mensagen de erro
			size_t length = regerror(code, &_regex, NULL, 0);

			//Limpa o buffer, caso ele não esteja vazio.
			if (buffer != NULL) {
				free(buffer);
				buffer = NULL;
			}

			//Aloca espaço para a mensagem de erro
			if ((buffer = (char*) malloc(length)) == NULL) {
				//LOG("Não foi possível alocar memória para a mensagem de erro.")
				return;
			}

			//Copia para buffer a mensagem de erro
			regerror(code, &_regex, buffer, length);
		}
		//--------------------------------------------------------------------------------
	} //namespace util
} //namespace bilbao
